<template>
    <div id="crud">
        <div class="pageLine1">
            <div class="headButtons">
                <AButton @click="onCreate ? onCreate() : handleCreate()" type="primary" class="addButton" shape="round">
                    <template #default>
                        {{ addText }}
                    </template>
                    <template #icon>
                        <PlusOutlined />
                    </template>
                </AButton>
                <slot name="headButtons" />
            </div>
            <AForm
                class="filterForm"
                ref="filterFormRef"
                v-if="$slots.filter"
                layout="inline"
                @reset="resetFilter"
                @finish="completeFilter"
                :model="innerFilterFormData"
            >
                <slot name="filter" />
                <AFormItem class="operatedBtns">
                    <AButton type="primary" htmlType="submit">搜索</AButton>
                    <AButton htmlType="reset">重置</AButton>
                </AFormItem>
            </AForm>
        </div>
        <div class="tableWrapper" ref="tableWrapperRef">
            <ATable
                :pagination="pagination ? paginationConfig : false"
                :scroll="scroll === true ? { y: tableScrollY, x: scrollX } : scroll === false ? {} : typeof scroll === 'object' ? scroll : {}"
                :columns="columns"
                :dataSource="dataSource.map((item, index) => ({ ...item, key: index }))"
            >
                <template #bodyCell="{ column, record }">
                    <slot name="bodyCell" :column="column" :record="record"></slot>
                    <span v-if="column.dataIndex === 'operation'" class="operatedBtns">
                        <AButton @click="column.onEdit ? column.onEdit({ column, record }) : handleEdit(record)" type="primary">编辑</AButton>
                        <APopconfirm @confirm="handleDelete(record)" :title="`确定删除${record[deleteMessageKey]}吗？`">
                            <AButton type="danger">删除</AButton>
                        </APopconfirm>
                        <slot name="operation" :column="column" :record="record"></slot>
                    </span>
                </template>
            </ATable>
            <AModal @ok="confirmForm" v-model:visible="modalVisible" :title="`${operationType === 'create' ? '添加' : '编辑'}`" :width="600">
                <ARow>
                    <ACol span="21">
                        <AForm @finish="confirmForm" ref="formRef" :model="innerFormData" v-bind="{ labelCol: { span: 6 }, wrapperCol: { span: 18 } }">
                            <AFormItem v-for="(item, index) in form" :key="index" :label="item.label || item.title" :name="item.dataIndex">
                                <AInput
                                    v-if="item.type === 'input' || item.type === undefined"
                                    v-model:value="innerFormData[item.dataIndex]"
                                    :placeholder="item.placeholder"
                                />
                                <AInputNumber
                                    v-if="item.type === 'inputNumber'"
                                    v-model:value="innerFormData[item.dataIndex]"
                                    :placeholder="item.placeholder"
                                    :min="item.min || 0"
                                    :max="item.max || Infinity"
                                />
                                <AInputPassword
                                    v-if="item.type === 'inputPassword'"
                                    v-model:value="innerFormData[item.dataIndex]"
                                    :placeholder="item.placeholder"
                                />
                                <ATextarea v-if="item.type === 'textarea'" v-model:value="innerFormData[item.dataIndex]" :placeholder="item.placeholder" />
                                <ASwitch
                                    v-if="item.type === 'switch'"
                                    v-model:checked="innerFormData[item.dataIndex]"
                                    :unCheckedChildren="itme.unCheckedChildren || '禁用'"
                                    :checkedChildren="item.checkedChildren || '可用'"
                                    :checkedValue="item.checkedValue || 1"
                                    :unCheckedValue="item.unCheckedValue || 0"
                                />
                                <ASelect v-if="item.type === 'select'" v-model:value="innerFormData[item.dataIndex]" :search="true">
                                    <ASelectOption v-for="(option, optionIndex) in item.options" :key="optionIndex" :value="option.value">
                                        {{ option.innerText || option.value }}
                                    </ASelectOption>
                                </ASelect>
                            </AFormItem>
                            <slot name="form" />
                        </AForm>
                    </ACol>
                    <ACol span="3"> </ACol>
                </ARow>
            </AModal>
        </div>
    </div>
</template>

<script>
import { PlusOutlined } from "@ant-design/icons-vue";
import { reactive, ref, toRefs, defineComponent, computed, onMounted } from "vue";
import { message } from "ant-design-vue";
import { useRoute, useRouter } from "vue-router";
import lodash from "lodash";
export default defineComponent({
    props: {
        columns: Array,
        createApi: Function,
        updateApi: Function,
        deleteApi: Function,
        getApi: Function,
        model: Object,
        formData: Object,
        initialFormData: Object,
        deleteMessageKey: {
            type: String,
            default: "title",
        },
        form: {
            type: Array,
            default: [],
        },
        scrollX: {
            type: Number,
            default: 1920,
        },
        scroll: {
            type: [Object, Boolean],
            default: false,
        },
        onCreate: Function,
        pagination: {
            type: Boolean,
            default: false,
        },
        paginationConfig: {
            type: Object,
            default: () => ({}),
        },
        page: [Number, undefined],
        pageSize: [Number, undefined],
        addText: {
            type: String,
            default: "添加",
        },
        filterFormData: Object,
        initialFilterFormData: Object,
        customEditRecord: {
            type: Function,
            default: record => record,
        },
        chainResult: {
            type: Function,
            default: result => result,
        },
        beforeModal: {
            type: Function,
            default: () => {},
        },
    },
    emits: { "update:formData": null, "update:filterFormData": null },
    components: {
        PlusOutlined,
    },
    setup(props, context) {
        const router = useRouter();
        const route = useRoute();
        const state = reactive({
            formRef: ref(),
            operationType: "create",
            modalVisible: false,
            operatedRecord: {},
            innerFormData: computed({
                get: () => props.formData,
                set: val => context.emit("update:formData", val),
            }),
            innerFilterFormData: computed({
                get: () => props.filterFormData,
                set: val => context.emit("update:filterFormData", val),
            }),
            dataSource: [],
            paginationConfig: {
                defaultCurrent: props.page || 1,
                defaultPageSize: props.pageSize || 10,
                pageSize: props.pageSize || 10,
                page: props.page || 1,
                total: 0,
                onChange(page, pageSize) {
                    state.paginationConfig.page = page;
                    state.paginationConfig.pageSize = pageSize;
                    getDataSource();
                    router.push({ path: route.path });
                },
                ...props.paginationConfig,
            },
        });
        const getDataSource = isReset => {
            let { page, pageSize } = state.paginationConfig;
            let params = {};
            if (props.pagination) {
                if (isReset) {
                    page = 1;
                    pageSize = 10;
                }
                params = { page, pageSize };
            }
            if (state.innerFilterFormData) {
                params = { ...params, ...state.innerFilterFormData };
            }
            return props.getApi(params).then(res => {
                if (res.code === 200) {
                    if (props.pagination) {
                        state.dataSource = res.data.data;
                        state.paginationConfig.total = res.data.total;
                    } else {
                        state.dataSource = res.data;
                    }
                }
            });
        };
        getDataSource();
        const confirmForm = () => {
            state.formRef.validate().then(result => {
                result = props.chainResult(result);
                if (state.operationType === "create") {
                    props.createApi(result).then(async res => {
                        if (res.code === 200) {
                            await getDataSource();
                            message.success("添加成功");
                            state.modalVisible = false;
                        }
                    });
                }
                if (state.operationType === "update") {
                    props.updateApi({ _id: state.operatedRecord._id, ...result }).then(async res => {
                        if (res.code === 200) {
                            await getDataSource();
                            message.success("更新成功");
                            state.modalVisible = false;
                        }
                    });
                }
            });
        };
        const handleDelete = record => {
            props.deleteApi({ _id: record._id }).then(async res => {
                if (res.code === 200) {
                    await getDataSource();
                    message.success("删除成功");
                }
            });
        };
        const tableWrapperRef = ref();
        const tableScrollY = ref(0);
        const calcScrollY = () => {
            let remainHeight = 40;
            if (props.pagination) {
                remainHeight += 64;
            }
            tableScrollY.value = tableWrapperRef.value.offsetHeight - remainHeight;
        };
        onMounted(() => {
            calcScrollY();
        });
        window.addEventListener("resize", e => {
            calcScrollY();
        });
        const filterFormRef = ref();
        const completeFilter = formData => {
            getDataSource();
        };
        const resetFilter = () => {
            state.innerFilterFormData = lodash.cloneDeep(props.initialFilterFormData);
            setTimeout(()=>{
                getDataSource(true);
            })
        };
        return {
            confirmForm,
            handleDelete,
            tableWrapperRef,
            tableScrollY,
            handleCreate() {
                props.beforeModal();
                state.operationType = "create";
                state.innerFormData = { ...props.initialFormData };
                state.modalVisible = true;
            },
            handleEdit(record) {
                props.beforeModal();
                state.innerFormData = props.customEditRecord(record);
                state.operationType = "update";
                state.operatedRecord = record;
                state.modalVisible = true;
            },
            ...toRefs(state),
            completeFilter,
            filterFormRef,
            resetFilter,
        };
    },
});
</script>

<style scoped lang="scss">
#crud {
    height: 100%;
    display: flex;
    flex-direction: column;
    .pageLine1 {
        margin-bottom: 20px;
        display: flex;
        flex-direction: column;
        .headButtons {
            display: flex;
            .addButton {
                align-self: flex-start;
            }
        }
        .filterForm {
            margin-top: 20px;
        }
    }
    .tableWrapper {
        flex: 1;
        overflow: hidden;
    }
}
</style>
